package com.alex.utils.http;

import java.security.KeyStore;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

import org.apache.http.client.HttpClient;
import org.apache.http.client.params.ClientPNames;
import org.apache.http.client.params.CookiePolicy;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.SingleClientConnManager;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.CoreConnectionPNames;
import org.apache.http.params.HttpParams;

import com.alex.utils.http.proxy.SocksProxySocketFactory;

public class HttpClientFactory {

	private int socketTimeout = 10000;

	private int connectionTimeout = 10000;

	private int maxRedirects = 10;

	private boolean threadSafe = true;

	private boolean handleRedirects = true;

	private int maxTotalConnections = 100;

	private int maxPerRouteTotalConnections = 100;

	public void setMaxTotalConnections(int maxTotalConnections) {
		this.maxTotalConnections = maxTotalConnections;
	}

	public void setMaxPerRouteTotalConnections(int maxPerRouteTotalConnections) {
		this.maxPerRouteTotalConnections = maxPerRouteTotalConnections;
	}

	public void setSocketTimeout(int socketTimeout) {
		this.socketTimeout = socketTimeout;
	}

	public void setConnectionTimeout(int connectionTimeout) {
		this.connectionTimeout = connectionTimeout;
	}

	public void setMaxRedirects(int maxRedirects) {
		this.maxRedirects = maxRedirects;
	}

	public void setThreadSafe(boolean threadSafe) {
		this.threadSafe = threadSafe;
	}

	public void setHandleRedirects(boolean handleRedirects) {
		this.handleRedirects = handleRedirects;
	}

	public HttpClient create() {
		HttpParams httpParams = new BasicHttpParams();
		httpParams.setParameter(CoreConnectionPNames.SO_TIMEOUT, socketTimeout);
		httpParams.setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, connectionTimeout);

		httpParams.setParameter(ClientPNames.HANDLE_REDIRECTS, handleRedirects);
		if (handleRedirects) {
			if (maxRedirects > 0) {
				httpParams.setParameter(ClientPNames.ALLOW_CIRCULAR_REDIRECTS, true);
				httpParams.setParameter(ClientPNames.MAX_REDIRECTS, maxRedirects);
			} else {
				httpParams.setParameter(ClientPNames.ALLOW_CIRCULAR_REDIRECTS, false);
			}
		}

		HttpClient httpClient = new DefaultHttpClient(getClientConnectionManager(), httpParams);
		httpClient.getParams().setParameter(ClientPNames.COOKIE_POLICY, CookiePolicy.BROWSER_COMPATIBILITY);

		return httpClient;
	}

	@SuppressWarnings("deprecation")
	private ClientConnectionManager getClientConnectionManager() {
		try {
			KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
	        trustStore.load(null, null);

	        SSLSocketFactory sf = new SSLSocketFactory(new TrustStrategy() {
	            public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
	                return true;
	            }
	        });
	        
	        sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
	        
	        SchemeRegistry schemeRegistry = new SchemeRegistry();
			schemeRegistry.register(new Scheme("http", 80, SocksProxySocketFactory.get()));
			schemeRegistry.register(new Scheme("https", 443, sf));
			
			if (threadSafe) {
				ThreadSafeClientConnManager connectionManager = new ThreadSafeClientConnManager(schemeRegistry);
				connectionManager.setMaxTotal(maxTotalConnections);
				connectionManager.setDefaultMaxPerRoute(maxPerRouteTotalConnections);
				return connectionManager;
			} else {
				return new SingleClientConnManager(schemeRegistry);
			}
			
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
}
